# -*- coding: utf-8 -*-
import os
import json
import pandas as pd
import sqlite3 # 导入sqlite3模块
from ai import AI
from tenacity import retry, stop_after_attempt, wait_random_exponential # 用于API调用重试

# --- LLM API 配置 ---
# 你需要根据你选择的LLM服务商进行配置
# 例如 OpenAI:
# import openai
# OPENAI_API_KEY = "YOUR_OPENAI_API_KEY" # 强烈建议使用环境变量
# openai.api_key = os.getenv("OPENAI_API_KEY", OPENAI_API_KEY)
# client = openai.OpenAI(api_key=openai.api_key)
# LLM_MODEL_NAME = "gpt-4-turbo-preview" # 或者 "gpt-3.5-turbo"

# 例如 Google Gemini:
# import google.generativeai as genai
# GOOGLE_API_KEY = "YOUR_GOOGLE_API_KEY" # 强烈建议使用环境变量
# genai.configure(api_key=os.getenv("GOOGLE_API_KEY", GOOGLE_API_KEY))
# gemini_model = genai.GenerativeModel('gemini-1.5-flash-latest') # 或者其他合适的模型

# --- 全局配置 ---
# 是否真的调用LLM API，设置为False时，会使用模拟数据，方便调试且不产生费用
ACTUALLY_CALL_LLM = True # !!! 重要：测试时设为False，实际运行时设为True !!!
SIMULATED_LLM_RESPONSE_DELAY = 0.1 # 模拟API调用延迟（秒）

@retry(wait=wait_random_exponential(min=1, max=60), stop=stop_after_attempt(5))
def call_llm(prompt: str, system_message: str = "You are a helpful assistant expert in Shopify app development and merchant needs analysis.", expect_json: bool = True) -> dict | str:
    """
    调用大型语言模型 (LLM) API 并获取响应。
    你需要根据你选择的LLM提供商的具体SDK来实现这个函数。

    参数:
        prompt (str): 发送给LLM的用户提示。
        system_message (str): 给LLM的系统级指令，设定其角色和背景。
        expect_json (bool): 是否期望LLM返回JSON格式的字符串。

    返回:
        dict | str: 如果expect_json为True且成功，返回解析后的字典。否则返回字符串。
                     如果API调用失败或JSON解析失败，会包含错误信息。
    """
    print(f"\n--- 准备调用LLM ---")
    print(f"System Message: {system_message[:100]}...") # 打印部分系统消息
    print(f"Prompt: {prompt[:200]}...") # 打印部分用户提示

    if not ACTUALLY_CALL_LLM:
        print("--- LLM调用模拟模式 ---")
        import time
        time.sleep(SIMULATED_LLM_RESPONSE_DELAY)
        if expect_json:
            # 模拟JSON输出 - 你需要根据你的prompt设计来调整这个模拟输出
            simulated_output = {
                "score": 7,
                "justification": "这是一个基于提示的模拟理由。",
                "confidence": "High",
                "keywords_indicating_pain": ["frustrated", "time sink"],
                "potential_value_proposition": "节省时间，提高效率。",
                "differentiation_opportunities": ["更好的用户体验", "更低的价格"]
            }
            # 随机化一点分数
            import random
            simulated_output["score"] = random.randint(3, 9)
            print(f"模拟 JSON 响应: {json.dumps(simulated_output, indent=2, ensure_ascii=False)}")
            return simulated_output # 直接返回字典
        else:
            simulated_output = "这是一个来自LLM的模拟文本响应。"
            print(f"模拟文本响应: {simulated_output}")
            return simulated_output

    try:
        ai = AI('deepseek-r1-250120')
        return ai.judge_idea(prompt)

        # 如果没有实际的LLM调用代码被取消注释并执行，下面的代码将运行
        raise NotImplementedError("实际的LLM API调用代码未实现或未取消注释。请编辑 call_llm 函数。")

    except Exception as e:
        print(f"LLM API 调用失败: {e}")
        if expect_json:
            return {"error": str(e), "score": 0, "justification": f"API调用失败: {e}"}
        return f"错误: {e}"

def get_pain_point_prompt(need_description: str, related_posts_summary: str = "") -> str:
    """为“痛点程度/紧急性”维度生成prompt。"""
    return f"""
    请分析以下Shopify商家需求：
    需求描述: "{need_description}"
    相关的论坛帖子摘要 (如有): "{related_posts_summary}"

    基于此信息，评估商家面临的“痛点程度/紧急性”。
    请考虑这个需求对商家有多关键。它是否阻碍销售、严重浪费时间，或者仅仅是轻微不便？

    请以JSON格式提供您的回复，包含以下键：
    - "score": 一个整数，范围从1（轻微不便）到10（关键的、阻碍业务的痛点）。
    - "justification": 对您分数的简要解释，如果可能，请引用描述或帖子中的证据。
    - "keywords_indicating_pain": 从输入中提取的表明痛苦或紧迫性的关键词或短语列表 (例如：["非常沮丧", "无法忍受"])。
    """

def get_monetization_prompt(need_description: str) -> str:
    """为“商业潜力/付费意愿”维度生成prompt。"""
    return f"""
    请分析以下Shopify商家需求：
    需求描述: "{need_description}"

    评估针对此需求的解决方案的“商业潜力/付费意愿”。
    请考虑商家是否可能为解决此问题的应用或服务付费。解决此需求是否能直接为商家带来收入增加、成本节约或效率显著提升？

    请以JSON格式提供您的回复，包含以下键：
    - "score": 一个整数，范围从1（付费意愿低）到10（付费意愿高，投资回报率明确）。
    - "justification": 对您分数的简要解释。
    - "potential_value_proposition": 您将如何向商家阐述此需求解决方案的价值？(例如："通过自动化X任务，每月节省Y小时")
    """

def get_innovation_prompt(need_description: str, existing_solutions_summary: str = "") -> str:
    """为“创新性/竞争格局”维度生成prompt。"""
    return f"""
    请分析以下Shopify商家需求：
    需求描述: "{need_description}"
    已知的现有解决方案或常见方法 (如有): "{existing_solutions_summary}"

    评估针对此需求开发新解决方案的“创新潜力/竞争优势”。
    请考虑：
    1. 这是一个新颖的问题，还是市场上已有许多现有解决方案？
    2. 如果存在解决方案，是否有显著改进的空间（例如，更好的用户体验、更低的价格、独特的功能、针对特定细分市场）？

    请以JSON格式提供您的回复，包含以下键：
    - "score": 一个整数，范围从1（已存在许多优秀解决方案，难以竞争）到10（高度创新，或市场存在明显空白）。
    - "justification": 对您分数的解释。
    - "differentiation_opportunities": 列出新解决方案可以脱颖而出的潜在方式 (例如：["专注于特定用户群体", "提供更简洁的界面"])。
    """

def get_technical_feasibility_prompt(need_description: str) -> str:
    """为“技术可行性/开发复杂度（初步感知）”维度生成prompt。"""
    return f"""
    请分析以下Shopify商家需求：
    需求描述: "{need_description}"

    基于您的通用知识和对Shopify平台能力的理解（假设您是一位经验丰富的Shopify应用开发者），初步评估实现此需求的“技术可行性/开发复杂度”。
    考虑因素可以包括：是否需要复杂的算法、是否依赖外部API、Shopify API是否原生支持相关功能、大致的开发工作量感知（高、中、低）。
    这不是一个精确的技术评估，而是一个基于需求描述的初步感知。

    请以JSON格式提供您的回复，包含以下键：
    - "score": 一个整数，范围从1（技术难度非常大，开发复杂且耗时）到10（技术上相对容易实现，开发复杂度较低）。
    - "justification": 对您分数的简要解释，指出潜在的技术挑战或简易性因素。
    - "potential_platform_dependencies": 可能依赖的Shopify API端点或核心功能 (例如：["Product API", "Order API", "Theme Liquid modifications"])。
    """


def analyze_single_need(need_data: dict) -> dict:
    """
    使用LLM分析单个需求。

    参数:
        need_data (dict): 包含需求信息的字典，至少应有 "id" 和 "description"。
                          可选: "frequency_score", "original_posts_summary", "existing_solutions_summary"

    返回:
        dict: 包含原始需求数据和LLM分析结果的字典。
    """
    # 确保使用 'description_cn' 或 'description'
    description_key = 'description_cn' if 'description_cn' in need_data else 'description'
    original_posts_summary_key = 'original_posts_summary_cn' if 'original_posts_summary_cn' in need_data else 'original_posts_summary'
    existing_solutions_summary_key = 'existing_solutions_summary_cn' if 'existing_solutions_summary_cn' in need_data else 'existing_solutions_summary'


    print(f"\nProcessing Need ID: {need_data.get('id', 'N/A')} - Title: {need_data.get('title', '')}...")

    analysis_result = need_data.copy() # 复制原始数据，然后添加分析结果

    # 1. 痛点程度/紧急性
    pain_prompt = get_pain_point_prompt(need_data.get(description_key, ''), need_data.get(original_posts_summary_key, ''))
    pain_analysis = call_llm(pain_prompt, system_message="您是一位Shopify商家痛点分析专家。", expect_json=True)
    analysis_result['pain_point_score'] = pain_analysis.get('score', 0) if isinstance(pain_analysis, dict) else 0
    analysis_result['pain_point_justification'] = pain_analysis.get('justification', 'LLM分析失败或返回非字典') if isinstance(pain_analysis, dict) else str(pain_analysis)
    analysis_result['pain_keywords'] = pain_analysis.get('keywords_indicating_pain', []) if isinstance(pain_analysis, dict) else []


    # 2. 商业潜力/付费意愿
    monetization_prompt = get_monetization_prompt(need_data.get(description_key, ''))
    monetization_analysis = call_llm(monetization_prompt, system_message="您是一位Shopify应用商业化分析专家。", expect_json=True)
    analysis_result['monetization_score'] = monetization_analysis.get('score', 0) if isinstance(monetization_analysis, dict) else 0
    analysis_result['monetization_justification'] = monetization_analysis.get('justification', 'LLM分析失败或返回非字典') if isinstance(monetization_analysis, dict) else str(monetization_analysis)
    analysis_result['value_proposition'] = monetization_analysis.get('potential_value_proposition', '') if isinstance(monetization_analysis, dict) else ''

    # 3. 创新性/竞争格局
    innovation_prompt = get_innovation_prompt(need_data.get(description_key, ''), need_data.get(existing_solutions_summary_key,''))
    innovation_analysis = call_llm(innovation_prompt, system_message="您是一位Shopify应用市场趋势与竞争格局分析专家。", expect_json=True)
    analysis_result['innovation_score'] = innovation_analysis.get('score', 0) if isinstance(innovation_analysis, dict) else 0
    analysis_result['innovation_justification'] = innovation_analysis.get('justification', 'LLM分析失败或返回非字典') if isinstance(innovation_analysis, dict) else str(innovation_analysis)
    analysis_result['differentiation_ops'] = innovation_analysis.get('differentiation_opportunities', []) if isinstance(innovation_analysis, dict) else []

    # 4. 技术可行性 (初步感知)
    tech_feasibility_prompt = get_technical_feasibility_prompt(need_data.get(description_key, ''))
    tech_feasibility_analysis = call_llm(tech_feasibility_prompt, system_message="您是一位经验丰富的Shopify应用架构师和开发者。", expect_json=True)
    analysis_result['tech_feasibility_score'] = tech_feasibility_analysis.get('score', 0) if isinstance(tech_feasibility_analysis, dict) else 0
    analysis_result['tech_feasibility_justification'] = tech_feasibility_analysis.get('justification', 'LLM分析失败或返回非字典') if isinstance(tech_feasibility_analysis, dict) else str(tech_feasibility_analysis)
    analysis_result['platform_dependencies'] = tech_feasibility_analysis.get('potential_platform_dependencies', []) if isinstance(tech_feasibility_analysis, dict) else []

    return analysis_result

def calculate_weighted_scores(analysis_results: list, weights: dict) -> list:
    """
    根据预设权重计算每个需求的加权总分。

    参数:
        analysis_results (list): 包含LLM分析结果的字典列表。
        weights (dict): 各评分维度的权重。
    返回:
        list: 更新了 "weighted_total_score" 键的字典列表，并按总分降序排列。
    """
    for result in analysis_results:
        total_weighted_score = 0
        for key, weight in weights.items():
            score_value = result.get(key, 0)
            if not isinstance(score_value, (int, float)):
                print(f"警告: 需求ID {result.get('id')} 的 {key} 不是数值类型 ({type(score_value)}), 将按0分计算。值为: {score_value}")
                score_value = 0
            total_weighted_score += score_value * weight
        result["weighted_total_score"] = round(total_weighted_score, 2)

    return sorted(analysis_results, key=lambda x: x.get("weighted_total_score", 0), reverse=True)

def load_needs_from_sqlite(db_path: str, table_name: str, column_mapping: dict) -> list:
    """
    从SQLite数据库加载需求数据。

    参数:
        db_path (str): SQLite数据库文件的路径。
        table_name (str): 包含需求数据的表名。
        column_mapping (dict): 一个字典，将数据库列名映射到脚本期望的键名。
                               例如: {"db_col_id": "id", "db_col_desc_cn": "description_cn", "db_col_freq": "frequency_score"}
                               脚本期望的键名包括: 'id', 'description_cn' (或 'description'),
                               'frequency_score', 'original_posts_summary_cn' (可选),
                               'existing_solutions_summary_cn' (可选)。

    返回:
        list: 从数据库加载并转换后的需求字典列表。
              如果发生错误，返回空列表。
    """
    print(f"正在从SQLite数据库加载数据: {db_path}, 表: {table_name}")
    needs_list = []
    if not os.path.exists(db_path):
        print(f"错误: 数据库文件 {db_path} 未找到。")
        return needs_list

    try:
        conn = sqlite3.connect(db_path)
        conn.row_factory = sqlite3.Row # 允许通过列名访问数据
        cursor = conn.cursor()

        # 构建SELECT查询的列名部分
        db_columns_to_select = list(column_mapping.keys())
        query = f"SELECT {', '.join(db_columns_to_select)} FROM {table_name};"
        print(f"执行SQL查询: {query}")

        cursor.execute(query)
        rows = cursor.fetchall()

        for row in rows:
            need_item = {}
            for db_col, script_key in column_mapping.items():
                need_item[script_key] = row[db_col]
            needs_list.append(need_item)

        conn.close()
        print(f"成功从数据库加载 {len(needs_list)} 条需求数据。")
    except sqlite3.Error as e:
        print(f"SQLite错误: {e}")
        print(f"请检查数据库路径、表名 ({table_name}) 和列名是否正确。")
        print(f"期望的数据库列 (来自column_mapping): {list(column_mapping.keys())}")
    except Exception as e:
        print(f"加载数据库数据时发生未知错误: {e}")

    return needs_list

def save_results_to_sqlite(db_path: str, table_name: str, results_data: list):
    """
    将分析结果保存到SQLite数据库。

    参数:
        db_path (str): SQLite数据库文件的路径。
        table_name (str): 用于存储分析结果的表名。
        results_data (list): 包含分析结果的字典列表。
    """
    if not results_data:
        print("没有分析结果可以保存到数据库。")
        return

    print(f"\n--- 准备将分析结果保存到SQLite数据库 ---")
    print(f"数据库: {db_path}, 表: {table_name}")

    try:
        conn = sqlite3.connect(db_path)
        cursor = conn.cursor()

        # 从第一个结果获取列名和类型，以创建表
        # 我们将所有文本类型都存储为TEXT，数值为REAL或INTEGER，列表/字典存储为TEXT (JSON字符串)
        sample_result = results_data[0]
        columns_definitions = []
        column_names = []

        for key, value in sample_result.items():
            column_names.append(key)
            if isinstance(value, bool): # SQLite没有布尔类型，用INTEGER 0或1
                 col_type = "INTEGER"
            elif isinstance(value, int):
                col_type = "INTEGER"
            elif isinstance(value, float):
                col_type = "REAL"
            elif isinstance(value, (list, dict)): # 将列表和字典存储为JSON字符串
                col_type = "TEXT"
            else: # 默认为TEXT
                col_type = "TEXT"
            columns_definitions.append(f'"{key}" {col_type}') # 使用双引号以支持特殊字符的列名

        # 创建表 (如果不存在)
        # 为了简单起见，如果表已存在并且结构不同，此代码不会处理迁移，而是会尝试插入。
        # 更健壮的实现会检查表结构或在插入前删除旧表。
        create_table_query = f"CREATE TABLE IF NOT EXISTS {table_name} ({', '.join(columns_definitions)})"
        print(f"执行SQL: {create_table_query}")
        cursor.execute(create_table_query)

        # 准备插入语句
        placeholders = ', '.join(['?'] * len(column_names))
        insert_query = f"INSERT INTO {table_name} ({', '.join([f'\"{col}\"' for col in column_names])}) VALUES ({placeholders})"
        print(f"准备插入查询模板: {insert_query}")


        # 插入数据
        records_to_insert = []
        for record in results_data:
            record_values = []
            for col_name in column_names:
                val = record.get(col_name)
                if isinstance(val, (list, dict)):
                    record_values.append(json.dumps(val, ensure_ascii=False)) # 序列化为JSON字符串
                elif isinstance(val, bool):
                    record_values.append(1 if val else 0) # 布尔转整数
                else:
                    record_values.append(val)
            records_to_insert.append(tuple(record_values))

        cursor.executemany(insert_query, records_to_insert)
        conn.commit()
        print(f"成功将 {len(records_to_insert)} 条记录保存到数据库表 '{table_name}'。")

    except sqlite3.Error as e:
        print(f"保存到SQLite数据库时发生错误: {e}")
        if conn:
            conn.rollback() # 如果发生错误，回滚事务
    except Exception as e:
        print(f"保存数据时发生未知错误: {e}")
        if conn:
            conn.rollback()
    finally:
        if conn:
            conn.close()

if __name__ == "__main__":
    print("--- Shopify需求LLM分析程序启动 (SQLite版) ---")

    # --- 数据库配置 ---
    DATABASE_FILE_PATH = "shopify_posts.db"  # <--- 修改为你的数据库文件名
    TABLE_NAME = "shopify_posts"                     # <--- 修改为你的表名
    OUTPUT_TABLE_NAME = "ideas"
    # 将你的数据库列名映射到脚本期望的键名
    # 确保这些数据库列确实存在于你的 'posts' 表中
    COLUMN_MAPPING = {
        "id": "id",                                  # 数据库中的帖子ID列 -> 'id'
        "title_cn": "title",
        "requirement": "description_cn",              # 数据库中的帖子中文内容列 -> 'description_cn'
        # "post_content_en": "description",               # 如果你用英文描述，取消注释这行并注释掉中文那行
        "replies": "frequency_score",        # 数据库中的需求频率分列 -> 'frequency_score'
        "summary": "original_posts_summary_cn", # (可选) 数据库中的相关帖子摘要列
        # "known_competing_apps_cn": "existing_solutions_summary_cn"  # (可选) 数据库中的已知竞品摘要列
    }
    # --- 结束数据库配置 ---


    # 1. 从SQLite数据库加载需求数据
    extracted_needs_list = load_needs_from_sqlite(DATABASE_FILE_PATH, TABLE_NAME, COLUMN_MAPPING)

    if not extracted_needs_list:
        print("未能从数据库加载数据，或数据库为空。将使用内置的模拟数据进行演示。")
        # 这里可以保留或移除模拟数据作为备用方案
        extracted_needs_list = [
            {"id": "N001", "description_cn": "商家希望根据供应商批量编辑产品标签。", "frequency_score": 8, "original_posts_summary_cn": "许多用户对逐个手动更新标签感到沮丧，称其“非常耗时”。"},
            {"id": "N002", "description_cn": "能够在不使用单独应用的情况下为批发客户提供分级折扣。", "frequency_score": 7, "original_posts_summary_cn": "Shopify Plus用户有Shopify Scripts，但其他商家需要更简单的解决方案，称其对B2B“至关重要”。", "existing_solutions_summary_cn": "一些第三方应用提供此类功能，但可能设置复杂或费用较高。"},
        ]
        if not extracted_needs_list: # 如果连模拟数据也没有了（比如被删掉）
             print("错误：无数据可处理。请检查数据库配置或提供模拟数据。程序即将退出。")
             exit()
        print(f"已加载 {len(extracted_needs_list)} 条模拟需求数据。")


    # 限制处理的需求数量以进行快速测试 (取消注释以启用)
    # extracted_needs_list = extracted_needs_list[:3]
    # print(f"注意：已限制处理数量为 {len(extracted_needs_list)} 条进行测试。")


    # 2. 对每条需求进行LLM分析
    all_analyzed_results = []
    if extracted_needs_list: # 确保有数据才进行分析
        for i, need_item in enumerate(extracted_needs_list):
            print(f"\n--- 开始分析第 {i+1}/{len(extracted_needs_list)} 条需求 ---")
            analyzed_item = analyze_single_need(need_item)
            all_analyzed_results.append(analyzed_item)
            # if ACTUALLY_CALL_LLM and i < len(extracted_needs_list) - 1:
            #     import time
            #     time.sleep(1) # 等待1秒，避免过于频繁调用API
    else:
        print("没有需求数据可供分析。")


    # 3. 定义权重并计算总分
    scoring_weights = {
        "frequency_score": 0.15,
        "pain_point_score": 0.25,
        "monetization_score": 0.25,
        "innovation_score": 0.15,
        "tech_feasibility_score": 0.20,
    }
    if abs(sum(scoring_weights.values()) - 1.0) > 1e-9 :
        print(f"警告: 权重总和 ({sum(scoring_weights.values())}) 不为1。请检查 scoring_weights。")

    if all_analyzed_results:
        final_ranked_results = calculate_weighted_scores(all_analyzed_results, scoring_weights)

        # 将结果保存到SQLite数据库
        save_results_to_sqlite(DATABASE_FILE_PATH, OUTPUT_TABLE_NAME, final_ranked_results)

        # (可选) 仍然打印部分结果到控制台以供快速预览
        print("\n部分排名靠前的结果预览 (来自内存中的数据):")
        temp_df_for_preview = pd.DataFrame(final_ranked_results)
        display_columns = ['id', 'weighted_total_score', 'pain_point_score', 'monetization_score', 'innovation_score', 'tech_feasibility_score']
        if 'description_cn' in temp_df_for_preview.columns:
            display_columns.insert(1, 'description_cn')
        elif 'description' in temp_df_for_preview.columns:
            display_columns.insert(1, 'description')
        existing_display_columns = [col for col in display_columns if col in temp_df_for_preview.columns]
        print(temp_df_for_preview[existing_display_columns].head())
    else:
        print("没有分析结果可以保存或预览。")

    print("\n--- 程序执行完毕 ---")
